package com.thoughtservice.jspdoc;


/* 
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is "JSP Documentation Generator Project of Alex Muc".
 * 
 * The Initial Developer of the Original Code is <a href="mailto:alex.muc@utoronto.ca">Alex Muc</a>.
 * Portions created by <a href="mailto:alex.muc@utoronto.ca">Alex Muc</a>
 * are Copyright (C) 2000 <a href="mailto:alex.muc@utoronto.ca">Alex Muc</a>.
 * All Rights Reserved.
 * 
 * Contributor(s): Alex Muc
 */


import java.util.*;
import java.io.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.thoughtservice.jspdoc.output.JSPPageEnum;

/**
 * Creation date: (2000-10-23 9:17:33 AM)
 * @author Alex Muc
 * @author Modified By Shinu Suresh
 */
public class JSPPage implements Comparable<JSPPage> {
	
	private static Logger LOG = LoggerFactory.getLogger(JSPPage.class);
			
	private String Name;
	private File Page;
	/**
	 * The top level of the jsp source directory tree.
	 */
	private String RootSourceDir;

	public static final int LINKSTO = 0;
	public static final int LINKSFROM = 1;
	public static final int S_INCLUDES = 2;
	public static final int S_INCLUDEDIN = 3;
	public static final int REDIRECTS = 4;
	public static final int D_INCLUDES = 5;
	public static final int D_INCLUDEDIN = 6;
	public static final int LINKSTOFORM = 7;
	public static final int ERRORPAGE = 8;
	
	public static final int TILE_INSERTS = 9;
	public static final int TILE_INSERTS_INPAGE = 10;
	
	public static final String TYPESTRING = "String";
	public static final String TYPEINT = "int";
	public static final String TYPEUNKNOWN = "UNKNOWN";

	public static final String SOURCEPARAMETER = "Parameter";
	public static final String SOURCESESSION = "Session";

	private Hashtable<File, Integer> LinksTo;
	private Hashtable<File, Integer> LinksFrom;
	private Hashtable<File, Integer> S_Includes;
	private Hashtable<File, Integer> S_IncludedIn;
	private Hashtable<File, Integer> Redirects;
	private Hashtable<File, Integer> D_Includes;
	private Hashtable<File, Integer> D_IncludedIn;
	private Hashtable<File, Integer> LinksToForm;
	private Hashtable<File, Integer> ErrorPage;
	
	private HashMap<String, File> TileInserts;
	private HashMap<String, File> TileInsertsIn;

	private TreeSet<String> Imports;

	/**
	 * Provides us with a means to store any extra data with the JSP Page.
	 * key = A <code>String</code> to name the data
	 * value = Some object which holds the data
	 * 
	 * @see #addExtraData(String key, Object o)
	 * @see #getExtraData(String key)
	 */
	private HashMap<String, Object> ExtraData;

	/**
	 * Key = (String) The name of the parameter
	 * Value = (String []) An array of 2 elements where the first element is the type of the
	 * parameter and the second element is the description of the parameter, both as Strings.
	 */
	private TreeMap<String, String[]> ParamNames;

	private java.lang.String PageDesc;
//	private String ErrorPage;
	
	
	/**
	 * JSPPage constructor comment.
	 */
	public JSPPage(File f, String rootSourceDir) {
		super();

		Page = f;
		RootSourceDir = rootSourceDir;
		
		setName(f.toString());

		LinksTo = new Hashtable<File, Integer>();
		LinksFrom = new Hashtable<File, Integer>();
		S_Includes = new Hashtable<File, Integer>();
		S_IncludedIn = new Hashtable<File, Integer>();
		Redirects = new Hashtable<File, Integer>();
		D_Includes = new Hashtable<File, Integer>();
		D_IncludedIn = new Hashtable<File, Integer>();
		LinksToForm = new Hashtable<File, Integer>();
		ErrorPage = new Hashtable<File, Integer>();
		
		TileInserts = new HashMap<String, File>();
		TileInsertsIn = new HashMap<String, File>();
		
		Imports = new TreeSet<String>();
		ParamNames = new TreeMap<String, String[]>();
		
		ExtraData = new HashMap<String, Object>();
	}
	
	/**
	 * Tests if this is a JSP page or a directory
	 */
	public boolean isPage() {
		return ! Page.isDirectory();
	}
	/**
	 * Creation date: (2000-10-23 9:21:16 AM)
	 * @param f java.io.File
	 */
	public void addConnection(int type, File f) {

		Hashtable<File, Integer> list = null;		
		if (type == LINKSTO)
			list = LinksTo;
		else if (type == LINKSFROM)
			list = LinksFrom;
		else if (type == S_INCLUDES)
			list = S_Includes;
		else if (type == S_INCLUDEDIN)
			list = S_IncludedIn;
		else if (type == D_INCLUDES)
			list = D_Includes;
		else if (type == D_INCLUDEDIN)
			list = D_IncludedIn;
		else if (type == REDIRECTS)
			list = Redirects;
		else if (type == LINKSTOFORM)
			list = LinksToForm;
		else if (type == ERRORPAGE)
			list = ErrorPage;
		
		else {
			LOG.error("Invalid connection type. returning..");
			return;
		}

		if(list != null){
			Integer count = (Integer) list.get(f);
			if (count == null)
				list.put(f, new Integer(1));
			else
				list.put(f, new Integer(count.intValue() + 1));
		}		

	}
	
	
	/**
	 * Creation date: (2000-10-23 9:21:16 AM)
	 * @param f java.io.File
	 */
	public void addConnection(int type, String s) {

		File f = new File(s);
		addConnection(type, f);

	}
	/**
	 * Creation date: (2000-10-23 9:21:16 AM)
	 * @param f java.io.File
	 */
	public void addImport(String packageName) {

		if (Imports.contains(packageName))
			return;
		else
			Imports.add(packageName);

	}
	/**
	 * Creation date: (2000-10-23 9:21:16 AM)
	 * @param f java.io.File
	 */
	public void addParameter(String param, String type, String desc, String source) {

		if (ParamNames.keySet().contains(param))
			return;
		else {
			String [] vals = new String [3];
			vals[0] = type;
			vals[1] = desc;
			vals[2] = source;
			ParamNames.put(param, vals);
			
		}

	}
	
	/**
	 * Add tile insert entries to TileInserts 
	 * @param packageName
	 */
	public void addTileInserts(String tileName, File f) {

		if (TileInserts.containsKey(tileName))
			return;
		else
			TileInserts.put(tileName, f);
	}
	
	/**
	 * Add tile insert entries to TileInserts In
	 * @param packageName
	 */
	public void addTileInsertsIn(String tileName, File f) {

		if (TileInsertsIn.containsKey(tileName))
			return;
		else
			TileInsertsIn.put(tileName, f);

	}
	
	public void addTileInserts(String tileName, String fileName) {

		File f = new File(fileName);
		addTileInserts(tileName, f);
	}
	
	public void addTileInsertsIn(String tileName, String fileName) {

		File f = new File(fileName);
		addTileInsertsIn(tileName, f);

	}
	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @return java.lang.String
	 */
	public Iterator<File> getConnections(int type) {
		if (type == LINKSTO)
			return LinksTo.keySet().iterator();
		else if (type == LINKSFROM)
			return LinksFrom.keySet().iterator();
		else if (type == S_INCLUDES)
			return S_Includes.keySet().iterator();
		else if (type == S_INCLUDEDIN)
			return S_IncludedIn.keySet().iterator();
		else if (type == D_INCLUDES)
			return D_Includes.keySet().iterator();
		else if (type == D_INCLUDEDIN)
			return D_IncludedIn.keySet().iterator();
		else if (type == REDIRECTS)
			return Redirects.keySet().iterator();
		else if (type == LINKSTOFORM)
			return LinksToForm.keySet().iterator();
		else if (type == ERRORPAGE)
			return ErrorPage.keySet().iterator();		
		/*	else if (type == )
				return .keySet().iterator();*/
		else
			return null;
	}
	
	public int getTypeSize(JSPPageEnum type){
		switch (type) {
		case LINKS_TO:
			return LinksTo.size();
		case LINKSFROM:
			return LinksFrom.size();	
		case S_INCLUDES:
			return S_Includes.size();	
		case S_INCLUDEDIN:
			return S_IncludedIn.size();	
		case REDIRECTS:
			return Redirects.size();	
		case D_INCLUDES:
			return D_Includes.size();
		case D_INCLUDEDIN:
			return D_IncludedIn.size();
		case LINKSTOFORM:
			return LinksToForm.size();
		case ERRORPAGE:
			return ErrorPage.size();
		case TILE_INSERTS:
			return TileInserts.size();
		case TILE_INSERTS_INPAGE:
			return TileInsertsIn.size();
		case IMPORTS:
			return Imports.size();
		case PARAMETERS:
			return ParamNames.size();
		default:
			break;
		}
		return 0;
	}

	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @return java.lang.String
	 */
	public Iterator<Integer> getConnectionsPages(int type) {
		if (type == LINKSTO)
			return LinksTo.values().iterator();
		else if (type == LINKSFROM)
			return LinksFrom.values().iterator();
		else if (type == S_INCLUDES)
			return S_Includes.values().iterator();
		else if (type == S_INCLUDEDIN)
			return S_IncludedIn.values().iterator();
		else if (type == D_INCLUDES)
			return D_Includes.values().iterator();
		else if (type == D_INCLUDEDIN)
			return D_IncludedIn.values().iterator();
		else if (type == REDIRECTS)
			return Redirects.values().iterator();
		else if (type == LINKSTOFORM)
			return LinksToForm.values().iterator();
		else if (type == ERRORPAGE)
			return ErrorPage.values().iterator();		
		/*	else if (type == )
				return .keySet().iterator();*/
		else
			return null;
	}


	/**
	 * Return all imports in page
	 * @return java.lang.String
	 */
	public Iterator<String> getImports() {
		return Imports.iterator();
	}
	
	/**
	 * Return all <tile:inserts
	 * @return java.lang.String
	 */
	public Iterator<String> getTileInserts() {
		return TileInserts.keySet().iterator();
	}
	
	/**
	 * Return all <tile:inserts used in the current JSP page
	 * @return java.lang.String
	 */
	public Iterator<String> getTileInsertsIn() {
		return TileInsertsIn.keySet().iterator();
	}
	
	public Iterator<File> getStaticIncludes() {
		return S_Includes.keySet().iterator();
	}
	public Iterator<File> getDynamicIncludes() {
		return D_Includes.keySet().iterator();
	}
	
	public File getTilePath(String key){
		if(key == null)
			return null;
		return TileInserts.get(key);						
	}
	
	public File getTileInPath(String key){
		if(key == null)
			return null;
		return TileInsertsIn.get(key);						
	}
	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @return java.lang.String
	 */
	public java.lang.String getName() {
		return Name;
	}
	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @return java.lang.String
	 */
	public java.lang.String getNameShort() {
		String file = new String(Name);
		file = file.replace('\\', '/');
		int ind = file.lastIndexOf("/");
		if (ind != -1) {
			return file.substring(ind + 1, file.length());
		}
		return file;
	}

	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @return java.lang.String
	 */
	public java.lang.String getNamePath() {
		
		String namePath = getName().substring(RootSourceDir.length(), getName().length());
		
		return namePath;
	}

	/**
	 * Creation date: (2000-10-24 2:21:14 PM)
	 * @return java.lang.String
	 */
	public java.lang.String getPageDesc() {
		return PageDesc;
	}


	/**
	 * Creation date: (2000-10-24 2:21:14 PM)
	 * @return java.lang.String
	 */
	public java.lang.String getPageDescShort() {
		if (PageDesc == null)
			return "";
			
		// Build a list of indexes for all the things we want to check
		// for to find the end marker of the short description.
		TreeSet<Integer> ts = new TreeSet<Integer>();
		ts.add(new Integer(PageDesc.indexOf(". ")));
		ts.add(new Integer(PageDesc.indexOf(".<")));
		ts.add(new Integer(PageDesc.indexOf(".\n")));
		
		// Find the lowest period greater than -1
		int period = -1;
		Iterator<Integer> i = ts.iterator();
		while (i.hasNext()) {
			Integer p = (Integer) i.next();
			if (p.intValue() > -1) {
				period = p.intValue();
				break;
			}
		}
			
		if (period != -1) {
			return PageDesc.substring(0, period + 1);
		}
		return PageDesc;
	}
	/**
	 */
	public Iterator<String> getParamDescs() {
		Vector<String> v = new Vector<String>();
		Iterator<String[]> i = ParamNames.values().iterator();
		while (i.hasNext()) {
			String [] ss = (String []) i.next();
			v.add(ss[1]);
		}
		return v.iterator();
	}
	/**
	 */
	public Iterator<String> getParamSources() {
		Vector<String> v = new Vector<String>();
		Iterator<String[]> i = ParamNames.values().iterator();
		while (i.hasNext()) {
			String [] ss = (String []) i.next();
			v.add(ss[2]);
		}
		return v.iterator();
	}
	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @return java.lang.String
	 */
	public Iterator<String> getParamNames() {
		return ParamNames.keySet().iterator();
	}
	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @return java.lang.String
	 */
	public Iterator<String> getParamTypes() {
		Vector<String> v = new Vector<String>();
		Iterator<String[]> i = ParamNames.values().iterator();
		while (i.hasNext()) {
			String [] ss = (String []) i.next();
			v.add(ss[0]);
		}
		return v.iterator();
	}
	/**
	 * Creation date: (2000-10-23 9:18:01 AM)
	 * @param newName java.lang.String
	 */
	public void setName(java.lang.String newName) {
		Name = newName;
	}
	/**
	 * Creation date: (2000-10-24 2:21:14 PM)
	 * @param newPageDesc java.lang.String
	 */
	public void setPageDesc(java.lang.String newPageDesc) {
		PageDesc = newPageDesc;
	}
	/**
	 * Creation date: (2000-10-23 9:30:47 AM)
	 * @return java.lang.String
	 */
	public String toString() {
		return getName();
	}

	public int compareTo(JSPPage o) {
		if (o instanceof JSPPage)
			return getName().toLowerCase().compareTo(((JSPPage) o).getName().toLowerCase());
		else
			return -1;
	}
	

	/**
	 * Store extra data about this JSP Page.
	 * 
	 * @param key String The name to store the data under
	 * @param o Object The data to store about the page
	 * @see #getExtraData(String key)
	 * @see #ExtraData
	 */	
	public void addExtraData(String key, Object o) {
		if (key != null && o != null) {
			ExtraData.put(key, o);
		}
	}

	

	/**
	 * Get extra data about this JSP Page.  This will retrieve the
	 * data stored under the given name for this page.
	 * 
	 * @param key String The name to get the data for
	 * @return o Object The data stored about the page under the given name
	 * @see #addExtraData(String key, Object o)
	 * @see #ExtraData
	 */	
	public Object getExtraData(String key) {
		if (key != null) {
			return ExtraData.get(key);
		}
		return null;
	}

	/**
	 * If there are multiple page descriptions, break it using html <br />
	 * @param descriptions
	 */
	public void setMultiPageDesc(String[] descriptions) {		
		for(String desc : descriptions){
			PageDesc = PageDesc.concat("<br />"+desc);
			//PageDesc = PageDesc + desc;			
		}
		LOG.info("Descriptions --> {}", PageDesc);
	}
}
